package com.carlinfo.usercenter.common.dao.impl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import com.carlinfo.usercenter.common.util.DbUtil;
import com.carlinfo.usercenter.common.util.PageInfoUtil;
import com.carlinfo.userscenter.users.pojo.AAdmins;
import com.carlinfo.userscenter.users.pojo.ARole;

/**
 * 此类是所有dao的公共类
 * 
 * T:表示泛型,在父类我不知道dao对应哪张表,想在父类里面使用某个类型(不定的)的对象,那就加T,占位符
 * 让子类来确定使用那张表的crud
 * T: 暂时理解为Object,在使用的时候,根据指定的类型确定T的类型
 * 在父类里面不能出现子类相关的类型 
 * @author jjh
 *
 */
public class BaseDaoImpl<T>
{
	/* 加载驱动和获取链接 */
	protected DbUtil dbUtil = DbUtil.getInstance();
	
	/**
	 * 把数据库里面的记录,变成java对象
	 * 利用反射
	 * @param rs
	 * @return
	 */
	protected T convertFromDb(T t ,ResultSet rs) throws SQLException
	{
		/*
		 * ~获取Class对象
		 * ~获取所有的method 
		 * */
		Class cla = t.getClass() ; 
		/* new一个对象
				 * 所有的属性全部是空的,
				 * 调用set方法赋值
				 *  */
		Object returnObj = null;
		try
		{
			returnObj = cla.newInstance();
		} catch (InstantiationException e1)
		{
			e1.printStackTrace();
		} catch (IllegalAccessException e1)
		{
			e1.printStackTrace();
		}
		
		/* 获取所有的字段 */
		Field[] fields = cla.getDeclaredFields() ; 
		for (int i = 0; i < fields.length; i++)
		{
			try
			{
				Field field = fields[i];
				/* 字段名 */
				String name = field.getName() ; 
				/*
				 * id = Id;
				 * setId ;
				 * */
				String setName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1,name.length());
				/*
				 * field.getType():获取属性的类型,
				 * 返回值是Class
				 * */
				//System.out.println(i + "===" + name + "--->" + setName + "--->" + field.getType().getSimpleName());
				Class fieldTypeClass = field.getType() ; 
				/* set方法
				 * setName
				 * 
				 * getMethod
				 * 参数1:指的是方法名;set+属性(首字母大写)
				 * 参数2:类型;有int,byte,string,Date
				 * 有待扩展,有可能填写Double,四类八种,都考虑到
				 *  */
				Method setMethod = null ; 
				/* 从数据库中取值
				 * POJO中的属性名和表的列名一样,
				 * 
				 * 如果是int,调用rs.getInt
				 * 如果是byte,调用rs.getByte()
				 * 
				 * dbObj = rs.getInt(name);
				 *  */
				Object dbObj = null ; 
				if(fieldTypeClass == int.class || fieldTypeClass == Integer.class)
				{
					setMethod = cla.getMethod(setName, int.class);
					dbObj = rs.getInt(name);
				}else if(fieldTypeClass == byte.class || fieldTypeClass == Byte.class)
				{
					setMethod = cla.getMethod(setName, byte.class);
					dbObj = rs.getByte(name);
				}else if(fieldTypeClass == double.class || fieldTypeClass == Double.class)
				{
					setMethod = cla.getMethod(setName, double.class);
					dbObj = rs.getDouble(name);
				}else if(fieldTypeClass == String.class)
				{
					setMethod = cla.getMethod(setName, String.class);
					dbObj = rs.getString(name);
				}else if(fieldTypeClass == Date.class)
				{
					setMethod = cla.getMethod(setName, Date.class);
					dbObj = rs.getTimestamp(name);
				}
				
				if(setMethod != null)
				{
					/* 执行setMethod
					 * setName("测试");的参数是赋值,要从数据库中取
					 * 
					 * 参数1:是对象,Class对应的对象
					 * 参数2:方法的形参对应的实参;
					 * setName方法可是木有返回值
					 *  */
					setMethod.invoke(returnObj, dbObj);
				}
			} catch (Exception e)
			{
				//e.printStackTrace();
			}
		}
		return (T) returnObj; 
	}
	
	/**
	 * 标准的jdbc 
	 * @param sql  执行的sql语句
	 * @param paramsList   sql语句的条件 
	 * @param t
	 * @return
	 */
	protected T findOneBase(String sql , List<Object> paramsList , T t)
	{
		/*------------------标准的JDBC------------------------*/
		Connection connection = this.dbUtil.getConnection() ;
		PreparedStatement ps = null ;
		ResultSet rs = null ;
		
		try
		{
			ps = connection.prepareStatement(sql);
			/**
			 * 设置条件
			 * 从Map中取值的时候,一定要确定有没有放进去
			 * 参数1:第几个？
			 * 参数2:为？赋值 
			 */
			//ps.setObject(1, condMap.get("id"));
			/* 有多少个？,就设置多少个条件 */
			int count = 1 ;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object paramsObj = (Object) iterator.next();
				ps.setObject(count, paramsObj);
				/* 计数器 */
				count ++ ;
			}
			rs = ps.executeQuery();
			/**
			 * 如果是多条用循环
			 * 如果是单条就是判断
			 */
			if(rs.next())
			{
				/* 将数据库里面的记录变成java对象 */
				t = convertFromDb(t , rs);
				return t;
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.colseAll(connection, ps, rs);
		}
		return null ;
	}
	
	/**
	 * 查询列表分页
	 * @param sql   执行的sql语句
	 * @param paramsList  存储sql语句条件的
	 * @param t  
	 * @return   返回分页的结果 
	 */
	
	protected List<T> findByPage(PageInfoUtil pageInfoUtil , String sql , List<Object> paramList , T t)
	{
		/*------------------标准的JDBC------------------------*/
		List<T> resultList = new ArrayList<T>();
		Connection connection = this.dbUtil.getConnection() ;
		PreparedStatement ps = null ;
		ResultSet rs = null ;
		try
		{
			if(pageInfoUtil != null)
			{
				System.out.println("=======获取总记录数=============");
				String fromIndex = "from" ;
				String orderByIndex = "order by" ;
				String countSql = "select count(*) " + sql.substring(sql.indexOf(fromIndex),sql.indexOf(orderByIndex));
				System.out.println("====总记录数Sql语句==" + countSql);
				/* 将sql语句发送到数据库 */
				ps = connection.prepareStatement(countSql);
				/* 设置条件 */
				int count = 1 ; 
				for (Iterator iterator = paramList.iterator(); iterator.hasNext();)
				{
					Object paramObj = (Object) iterator.next();
					ps.setObject(count, paramObj);
					count ++ ; 
				}
				rs = ps.executeQuery();
				/* 总记录数,肯定有一条结果 */
				if(rs.next())
				{
					/* 取第一列 */
					int totalRecord = rs.getInt(1);
					pageInfoUtil.setTotalRecord(totalRecord);
				}
				
				rs.close();
				ps.close();
				System.out.println("============分页开始(发送第二条sql语句)========");
				/* select * from a_role limit 1,5*/
				sql = sql + "limit ?,?" ;
				/* 查询分页数据 */
				ps = connection.prepareStatement(sql);
				/* 设置条件 */
//				ps.setObject(1, pageInfoUtil.getCurrentRecord());
//				ps.setObject(2, pageInfoUtil.getPageSize());
//				rs = ps.executeQuery();
				
				/* 把条件统一放到List中 */
				paramList.add(pageInfoUtil.getCurrentRecord());
				paramList.add(pageInfoUtil.getPageSize());
				
				
			}
				/* 查询所有数据 */
				ps = connection.prepareStatement(sql);
				/* 设置条件 */
				int count = 1 ; 
				for (Iterator iterator = paramList.iterator(); iterator.hasNext();)
				{
					Object paramObj = (Object) iterator.next();
					ps.setObject(count, paramObj);
					count ++ ; 
				}
				rs = ps.executeQuery();
			
			System.out.println("========查询记录============");
			
			/**
			 * 如果是多条用循环
			 * 如果是单条就是判断
			 */
			while(rs.next())
			{
				/* 把数据库里面的记录变成java对象 */ 
				t = convertFromDb(t , rs);
				/* 把role添加到集合中 */
				resultList.add(t);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.colseAll(connection, ps, rs);
		}
		return resultList;
	}
	/**
	 * 查询列表不分页 
	 * @param sql
	 * @param paramList
	 * @param t
	 * @return
	 */
	protected List<T> find(String sql , List<Object> paramList , T t)
	{
		/*-----------------标准的JDBC-------------------*/
		List<T> resultList = new ArrayList<T>();
		PreparedStatement ps = null ;
		ResultSet rs = null ; 
		Connection connection = this.dbUtil.getConnection() ; 
		try
		{
			/* 查询所有数据 */
			ps = connection.prepareStatement(sql);
			/* 设置条件 */
			int count = 1 ; 
			for (Iterator iterator = paramList.iterator(); iterator.hasNext();)
			{
				Object paramObj = (Object) iterator.next();
				ps.setObject(count, paramObj);
				count ++ ; 
			}
			rs = ps.executeQuery();
			
			//System.out.println("=========查询记录================");
			
			/* 如果是多条,使用循环
			 * 如果是单条,使用判断 */
			while(rs.next())
			{
				/* 将数据库里面的记录变成JAVA对象 */
				t = this.convertFromDb(t, rs);
				/* 把admins放到集合中 */
				resultList.add(t);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.colseAll(connection, ps, rs);
		}
		return resultList;
	}
	
	/**
	 * 执行一条sql语句 
	 * @param sql
	 * @param paramsList
	 * @return
	 */
	protected int executeSqlUpdate(String sql , List<Object> paramsList)
	{
		/*-------------标准的JDBC-------------*/
		int res = 0 ;
		Connection connection = this.dbUtil.getConnection();
		PreparedStatement ps = null ;
		ResultSet rs = null ;
		try
		{
			ps = connection.prepareStatement(sql ,Statement.RETURN_GENERATED_KEYS);
			/* 为条件赋值 */
			int paramsIndex = 1 ;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object paramObj = (Object) iterator.next();
				ps.setObject(paramsIndex, paramObj);
				paramsIndex ++ ;
			}
			/**
			 * 返回值:res的含义,执行sql语句对数据库影响的条数
			 */
			res = ps.executeUpdate();
			/**
			 * 获取主键
			 */
			rs = ps.getGeneratedKeys();
			if(rs.next())
			{
				int id = rs.getInt(1);
				/* 保存方法执行的结果时,要么使用返回值,要么参数返回 */
				paramsList.add(id);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.colseAll(connection, ps, null);
		}
		return res;
	}
}
